// -*- c-basic-offset: 2 default-tab-width: 2 indent-tabs-mode: t -*-
// vim: autoindent tabstop=2 noexpandtab shiftwidth=2 softtabstop=2
#include <limits.h>
#include "Const.h"
#include "Array.h"
#include "Symbol.h"
#include "File.h"

using namespace R;
//Null *ConstPool::Null;
Logical *ConstPool::True;
Logical *ConstPool::False;
Any *ConstPool::Null = NULL;

const char * ConstPool::NA_STRING = "NA"; // Actually I'm not really sure this is a good idea
const char * ConstPool::TRUE_STRING = "TRUE"; // Actually I'm not really sure this is a good idea
const char * ConstPool::FALSE_STRING = "FALSE"; // Actually I'm not really sure this is a good idea
const char * ConstPool::HomeDir;
const char * ConstPool::Path;
const char * ConstPool::ReactorPath;


static const union { double asDouble ; int asWord[2]; }
	true_double_na = { .asWord = { 0x7ff00000, 1954 } } ; // Check Endieness

const int ConstPool::NA_INT = INT_MIN;
const unsigned ConstPool::NA_LOG = (unsigned)INT_MIN;
const double ConstPool::NA_DOUBLE = true_double_na.asDouble ;

const double ConstPool::InfPos = 1.0/0.0;
const double ConstPool::InfNeg = -1.0/0.0;
const double ConstPool::NaN = 0.0/0.0;

ConstPool::ConstPool(int cap){
	capacity = cap;
	size = 0;
	data = new Any*[cap];
}

void ConstPool::initConsts(){
	// *** Grrr cannot init some const staticaly (due to this vmkit bug,
	// nor inside the constructor ...).
	
	// Anyway this variable are not at the right place, we need to define them somewhere else
	if(True)
		rfatal("Constants allready created, this is probably a bug.");

	True = Logical::doNewSingle(1);
	False = Logical::doNewSingle(0);
	HomeDir = getenv("HOME");
	Path = getenv("PATH");
	ReactorPath = getenv("REACTOR_PATH");
	File::init();
}

void ConstPool::loadPool(int size, cpool_entry *cpool_orig){
	ConstPool *self = this;

	if(this->size + size > capacity)
		enlargePool(size);

	Any **cpool = data + this->size; // FIXME this whole pool will not support
						// multiple loading since some id need to be reloacated
	Any ** current = cpool;
	this->size += size;

	cpool_entry* cp_ptr = cpool_orig;

	while(size--) {
		*(current++) = mkconst(cp_ptr++, cpool_orig, cpool);
	}
}

Any *ConstPool::operator[](int idx){
	Assert(idx < size, "Const pool overflow;");
	return data[idx];
}

void ConstPool::enlargePool(int cap){
	nyi();
}

Any *ConstPool::mkconst(cpool_entry *pe, cpool_entry *cpool_src, Any**cpool_dest){
  R_VAR(Any*, tmp);
  R_VAR(Int*, tmpint);
  R_VAR(Double*, tmpdbl);
  R_VAR(String*, tmpstr);
  R_VAR(Symbol*, tmpsym);
  R_VAR(Logical*, tmplgl);
  int len;

  switch(pe->type){
    case CPOOL_NULL:
			return ConstPool::Null;
    case CPOOL_INTSXP:
      len = pe->data.pe_int.size;
      tmpint = Int::doNew(len);
      memcpy(&tmpint->content, pe->data.pe_int.values, len*sizeof(tmpint->dataType));
      tmp = tmpint;
      break;
		case CPOOL_LGLSXP:
      len = pe->data.pe_lgl.size;
      tmplgl = Logical::doNew(len);
      memcpy(&tmplgl->content, pe->data.pe_int.values, len*sizeof(tmplgl->dataType));
      tmp = tmplgl;
      break;
     case CPOOL_DBLSXP:
      len = pe->data.pe_real.size;
      tmpdbl = Double::doNew(len);
      memcpy(&tmpdbl->content, pe->data.pe_real.values, len*sizeof(tmpdbl->dataType));
      tmp = tmpdbl;
      break;
    case CPOOL_STRSXP:
      len = pe->data.pe_vector.size;
      tmpstr = String::doNew(len);
      for(int i = 0; i < len; i++)
        tmpstr->setElement(cpool_src[pe->data.pe_vector.values[i]].data.pe_char.value, i);
      tmp = tmpstr;
      break;
    case CPOOL_STR:
      len = pe->data.pe_char.size;
      tmpsym = SymbolTable::lookup(len, pe->data.pe_char.value);
      return tmpsym;
      break;
    default:
      rfatal("Unimplemented constant type: %2x", pe->type);
      break;
  }
  if(pe->data.pe_int.names >= 0) {
    tmp->attributes = cpool_dest[pe->data.pe_int.names];
  }
  return tmp;
}
